import os
import logging

import numpy as np
import pandas as pd
from pandas import Series
from pandas.core.interchange.dataframe_protocol import DataFrame
from Basic import Basic

import common.utils
# from tools import _get_files_name as get_files_name
from tools import BASE_PATH_企业级应用课设
from tools import *
from common import utils
from file import get_files_name
from file import check_filename_format, has_duplicates

logging.basicConfig(
    level=logging.DEBUG,
    format='%(levelname)8s: %(message)s'
)

文档 = '([^-\.]+)'
班级 = '([^-\.]+)'
学号 = '([0-9]{11})'
姓名 = '([^-\.]+)'
日期 = '([0-9]{4})'
时长 = '([0-9]+)'
后缀 = '([^-\.]+)'

BASE_PATH = r"D:\100-Project\2025-2026-1学期安排\首义学院\19201017_《企业级应用开发课程设计（企业）》"
PATTERN_报告 = f'^{文档}-{班级}-{学号}-{姓名}.{日期}.{后缀}$'
PATTERN_视频 = f'^{班级}-{学号}-{姓名}.{日期}_{时长}.{后缀}$'


class 课设(Basic):

    def __init__(self):
        super().__init__()

        self.base_path = BASE_PATH
        self.学生名单_file_path = f"{self.base_path}\学生提交\学生名单.xlsx"
        self.报告_folder_path = f"{self.base_path}\学生提交\报告"
        self.视频_folder_path = f"{self.base_path}\学生提交\视频"
        self.output_file = f"{self.base_path}\学生提交\成绩输出.xlsx"

        self.报告_filenames: Series = pd.Series(dtype=str)
        self.视频_filenames: Series = pd.Series(dtype=str)

        self.学生名单: DataFrame = pd.DataFrame(['学号', '姓名'])
        self.设计表现: DataFrame = pd.DataFrame(['学号', '设计表现'])  # 分值30分
        self.答辩情况: DataFrame = pd.DataFrame(['学号', '答辩情况'])  # 分值50分
        self.设计报告: DataFrame = pd.DataFrame(['学号', '设计报告'])  # 分值50分
        self.设计成果: DataFrame = pd.DataFrame(['学号', '设计成果'])  # 分值50分

        # self.output_file = f"{self.base_path}\学生提交\报告.xlsx"

        self.filenames: Series = pd.Series(dtype=str)
        self.ids = pd.Series(dtype=int)
        self.names = pd.Series(dtype=str)

        self.stu_list: DataFrame = pd.DataFrame(columns=['学号', '姓名'])
        self.commited_list: DataFrame = pd.DataFrame(columns=['学号', '姓名', '日期', '设计表现'])
        self.all_list: DataFrame = pd.DataFrame(columns=['学号', '姓名', '日期', '设计表现'])

    def get_学生名单(self, reload=False) -> DataFrame:
        if (reload is False) and (self.学生名单.shape[0] == 0):
            return self.学生名单

        self.学生名单 = self.get_stu_list(self.学生名单_file_path)
        return self.学生名单

    def get_报告_filenames(self, reload=False) -> Series:
        if (reload is False) and (not self.报告_filenames.empty):
            return self.报告_filenames

        filenames = self.get_filenames_in_folder(self.报告_folder_path, ['.doc', '.docx'])
        self.check_filenames_duplicates(filenames)

        self.报告_filenames = filenames
        return self.报告_filenames

    def get_视频_filenames(self, reload=False) -> Series:
        if (reload is False) and (not self.视频_filenames.empty):
            return self.视频_filenames

        filenames = self.get_filenames_in_folder(self.视频_folder_path, ['.mkv', '.mp4'])
        self.check_filenames_duplicates(filenames)

        self.视频_filenames = filenames
        return self.视频_filenames

    def get_设计表现(self, reload=False) -> DataFrame:
        if (reload is False) and (self.设计表现.shape[0] == 0):
            return self.设计表现

        BASE_SCORE = 28

        报告_filenames = self.get_报告_filenames()
        se_学号 = self.extract_parts_from_filename(报告_filenames, PATTERN_报告, 3).astype(int)
        se_日期 = self.extract_parts_from_filename(报告_filenames, PATTERN_报告, 5).astype(str)
        se_date = convert_mmdd_to_date(se_日期)

        min_date = se_date.min()  # 1. 找到最早日期
        days_diff = (se_date - min_date).dt.days  # 2. 计算每个日期与最早日期的天数差
        se_成绩 = BASE_SCORE - (days_diff + 1) // 2

        self.设计表现 = pd.DataFrame({'学号': se_学号, '设计表现': se_成绩})
        return self.设计表现

    def get_答辩情况(self, reload=False) -> DataFrame:
        if (reload is False) and (self.答辩情况.shape[0] == 0):
            return self.答辩情况

        视频_filenames = self.get_视频_filenames()
        se_学号 = self.extract_parts_from_filename(视频_filenames, PATTERN_视频, 2).astype(int)
        se_时长 = self.extract_parts_from_filename(视频_filenames, PATTERN_视频, 5).astype(int)

        # region 修正超长长度的时长
        se_时长 = self.fix_时长(se_时长)
        # endregion

        # region 算分
        min_target = 25  # 分数下限
        max_target = 48  # 分数上限

        # 计算原始数据的最小值和最大值
        min_x = se_时长.min()
        max_x = se_时长.max()
        se_scaled = min_target + (se_时长 - min_x) * (max_target - min_target) / (max_x - min_x)
        se_答辩情况 = se_scaled.astype(int)

        # region 修正最高分 50 分
        # se_答辩情况[se_答辩情况 > 48] = 48
        # endregion

        self.答辩情况 = pd.DataFrame({'学号': se_学号, '答辩情况': se_答辩情况})
        return self.答辩情况

    def get_设计报告(self, reload=False) -> DataFrame:
        if (reload is False) and (self.设计报告.shape[0] == 0):
            return self.设计报告

        报告_filenames = self.get_报告_filenames()
        se_学号 = self.extract_parts_from_filename(报告_filenames, PATTERN_报告, 3).astype(int)
        se_页数 = self.get_文档_页数(self.报告_folder_path, 报告_filenames)

        # region 修正极大页数
        se_页数 = self.fix_页数(se_页数)
        # endregion

        # region 计算设计报告分数（满分50分）
        se_设计报告 = (25 - (se_页数 - 25).abs()) * 2
        se_设计报告[se_设计报告 > 40] = se_设计报告 - 5
        # 四舍五入对齐到 5 的倍数
        se_设计报告 = ((se_设计报告 - 2) / 5).apply(np.floor).astype(int) * 5
        # region

        self.设计报告 = pd.DataFrame({'学号': se_学号, '设计报告': se_设计报告})

        return self.设计报告

    def get_设计成果(self, reload=False) -> DataFrame:
        if (reload is False) and (self.设计成果.shape[0] == 0):
            return self.设计成果

        视频_filenames = self.get_视频_filenames()
        se_学号 = self.extract_parts_from_filename(视频_filenames, PATTERN_视频, 2).astype(int)
        df = self.get_答辩情况()
        se_答辩情况 = df.loc[:, '答辩情况']

        # region 向上取整到5的倍数
        se_设计成果 = ((se_答辩情况 + 7) / 5).apply(np.ceil) * 5

        # 限制最大值为48
        se_设计成果 = se_设计成果.clip(upper=48)
        # 转换回整数类型
        se_设计成果 = se_设计成果.astype(int)
        # endregion

        se_设计成果 = (se_设计成果 / 5).apply(np.floor).astype(int) * 5
        self.设计成果 = pd.DataFrame({'学号': se_学号, '设计成果': se_设计成果})

        return self.设计成果

    def get_total(self) -> DataFrame:
        df_学生名单 = self.get_学生名单()
        df_设计表现 = self.get_设计表现()
        df_答辩情况 = self.get_答辩情况()
        df_设计报告 = self.get_设计报告()
        df_设计成果 = self.get_设计成果()

        df_merged = self.merge_dataframes([df_学生名单, df_设计表现, df_答辩情况, df_设计报告, df_设计成果], how='left')

        # region 处理空数据
        min_设计表现 = df_merged['设计表现'].min()
        min_答辩情况 = df_merged['答辩情况'].min()
        min_设计报告 = df_merged['设计报告'].min()
        min_设计成果 = df_merged['设计成果'].min()

        df_merged.fillna({'设计表现': min_设计表现 - 1}, inplace=True)
        df_merged.fillna({'答辩情况': min_答辩情况 - 1}, inplace=True)
        df_merged.fillna({'设计报告': min_设计报告 - 1}, inplace=True)
        df_merged.fillna({'设计成果': min_设计成果 - 1}, inplace=True)
        # endregion

        return df_merged


if __name__ == "__main__":
    课设 = 课设()

    # df_学生名单 = 课设.get_学生名单()
    # df_学生名单  = 课设.get_stu_list(课设.学生名单_file_path)
    # print(df_学生名单)

    # se_报告_filename = 课设.get_报告_filenames()
    # print(se_报告_filename)

    # se_视频_filename = 课设.get_视频_filenames()
    # print(se_视频_filename)

    # df = 课设.get_设计表现()
    # df = 课设.get_答辩情况()
    # df = 课设.get_设计报告()
    # df = 课设.get_设计成果()
    df = 课设.get_total()
    # print(df)
    df.to_excel(课设.output_file, index=False)
    print(f"✅ 数据合并完成! 文件已保存至: {课设.output_file}")
